<?php

namespace PSC\Model;

/**
 * Camada de Modelo
 *
 * Existe a necessidade de construção de uma camada de modelo mais genérica para
 * desenvolvimento, preocupando-se com gerenciamento de mensagens internas. Com
 * isto, podemos adicionar uma classe que efetue o gerenciamento destas
 * mensagens conforme necessário, apresentando os erros internos gerados em
 * tempo de execução para outras camadas. Esta classe nunca deve ser utilizada
 * como elemento no sistema e sim como base para especialização.
 *
 * @category PSC
 * @package  PSC\Model
 */
abstract class ModelAbstract
{
    /**
     * Mensagens Armazenadas
     * @var array
     */
    protected $_messages = array();

    /**
     * Composição de Camadas de Modelo
     * @var array
     */
    protected $_elements = array();

    /**
     * Configuração de Mensagem
     *
     * Cada mensagem deve ser adicionada relacionando-se com um identificador
     * dentro da camada de modelo. Estas mensagens são armazenadas para que
     * outras camadas consigam consultar os erros internos ocorridos. As
     * mensagens somente podem ser configuradas internamente à camada.
     *
     * @param  string        $identifier Identificador da Mensagem
     * @param  string        $content    Conteúdo para Configuração
     * @return ModelAbstract Próprio Objeto para Encadeamento
     */
    protected function _setMessage($identifier, $content)
    {
        // Conversão
        $identifier = (string) $identifier;
        $content    = (string) $content;
        // Identificador Inicializado?
        if (!array_key_exists($identifier, $this->_messages)) {
            // Inicialização
            $this->_messages[$identifier] = array();
        }
        // Configurar Conteúdo de Mensagem
        $this->_messages[$identifier][] = $content;
        // Encadeamento
        return $this;
    }

    /**
     * Captura de Mensagens
     *
     * Quando as mensagens são configuradas internamente à camada de modelo,
     * podemos capturá-las utilizando este método. Apresentando um
     * identificador, é possível capturar um conjunto de mensagens específicas,
     * caso contrário todas as mensagens configuradas na camada são
     * apresentadas.
     *
     * @param  string|null $identifier Identificador da Mensagem Requerida
     * @return array       Conjunto de Informações Solicitadas
     */
    public function getMessages($identifier = null)
    {
        // Resultado Inicial
        $result = array();
        // Tipagem de Identificador
        if ($identifier === null) {
            // Apresentar Todas as Mensagens
            $result = $this->_messages;
        } else {
            // Verificar Identificador Inicializado
            if (array_key_exists($identifier, $this->_messages)) {
                // Captura de Mensagens
                $result = $this->_messages[$identifier];
            }
        }
        // Apresentação
        return $result;
    }

    /**
     * Composição de Camadas de Modelo
     *
     * Utilizando o padrão de projeto Composite, podemos incluir muitas camadas
     * de modelo e construir um elemento capaz de mapear informações dentro do
     * sistema, distribuindo informações entre diferentes objetos. Cada elemento
     * interno possui um identificador que corresponde à responsabilidade no
     * conjunto. Somente um elemento de cada identificador pode ser configurado.
     *
     * @param  string        $identifier Identificador do Elemento na Camada
     * @param  ModelAbstract $element    Elemento para Composição
     * @return ModelAbstract Próprio Objeto para Encadeamento
     */
    public function setElement($identifier, ModelAbstract $element)
    {
        // Conversão
        $identifier = (string) $identifier;
        // Configuração
        $this->_elements[$identifier] = $model;
        // Encadeamento
        return $this;
    }

    /**
     * Captura de Elementos da Composição
     *
     * As camadas de modelo podem ser aninhadas visando construir elementos
     * capazes de centralizar um conjunto de estruturas, visando melhor
     * gerenciamento. Cada elemento interno possui um identificador único que
     * pode ser apresentado para captura.
     *
     * @param  string             $identifier Identificador do Elemento
     * @return ModelAbstract|null Elemento Solicitado ou Valor Nulo
     */
    public function getElement($identifier)
    {
        // Resultado Inicial
        $element = null;
        // Conversão
        $identifier = (string) $identifier;
        // Captura
        if (array_key_exists($identifier, $this->_elements)) {
            $element = $this->_elements[$identifier];
        }
        // Apresentação
        return $element;
    }
}

